#region Microsoft Public License
/*
 * (c) Copyright Chenjun Wu. http://utablesdk.codeplex.com
 * 
 * This source is subject to the Microsoft Public License (Ms-PL).
 * Please see http://go.microsoft.com/fwlink/?LinkID=131993 for details.
 * All other rights reserved.
 */
#endregion

using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Threading;
using UTable.Input;
using UTable.Input.MultiTouch;
using UTable.Input.Text;
using UTable.ObjectManager.Commands;
using UTable.Objects;
using UTable.Objects.Policies;


namespace UTable.ObjectManager
{
    public class GlobalObjectManagerImpl: IGlobalObjectManager
    {
        private IObjectTree _objectTree;

        private IInputManager _inputManager;

        private Dispatcher _dispatcher;

        private ILocalObjectManager _defaultLocalObjectManager;

        public GlobalObjectManagerImpl()
        {
            _dispatcher = Application.Current.Dispatcher;

            // set the default local object manager
            _defaultLocalObjectManager = new ULocalObjectManager();
            _defaultLocalObjectManager.LayoutPolicy = new LayoutPolicy(null, null);
        }

        private void OnInputDetected(ManagedInputEventArgs args)
        {
            try
            {
                List<ICommand> commands = new List<ICommand>();

                commands.Add(new ObjectCommand(args.Receiver as IObject, ObjectCommandType.Input, args.Args));

                if (args.Args is MultiTouchEventArgs)
                    (args.Args as UTable.Input.MultiTouch.MultiTouchEventArgs).FingerEvents[0].TimeTrace.GlobalObjectManagerTime = InputEventArgs.GetTimestamp();
                // (args.Args as UTable.Input.MultiTouch.MultiTouchEventArgs).FingerEvents[0].TimeTrace.SetStep(1);
                else if (args.Args is TextInputEventArgs) Console.Write("");
                else 
                {
                    MessageBox.Show(String.Format("In GlobalObjectManagerImpl.cs OnInputDetected, {0}", args.Args.GetType()));
                }

                PutCommands(commands);
            }
            catch (System.Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }
        }

        public Dispatcher Dispatcher
        {
            get { return _dispatcher; }
        }


        public void RegisterLayoutPolicy(Type objectType, Type layoutPolicyType, object[] startupParameters)
        {

        }

        public void RegisterAuthorizationPolicy(Type objectType, Type authorizationPolicyType, object[] startupParameters)
        {

        }

        public void RegisterConflictResolvePolicy(Type objectType, Type conflictResolvePolicyType, object[] startupParameters)
        {

        }

        public void SetLayoutPolicy(IObject obj, Type layoutPolicyType, object param)
        {
            (obj as IObjectEntity).LocalObjectManager.LayoutPolicy = 
                Activator.CreateInstance(layoutPolicyType, new object[] {obj, param}) as LayoutPolicy;
        }

        public void UpdateLayoutPolicy(IObject obj, object param)
        {
            (obj as IObjectEntity).LocalObjectManager.LayoutPolicy.UpdateParameter(param);
        }

        public void SetAuthorizationPolicy(IObject obj, Type authorizationPolicyType, object param)
        {
            (obj as IObjectEntity).LocalObjectManager.AuthorizationPolicy =
                Activator.CreateInstance(authorizationPolicyType, new object[] { obj, param }) as AuthorizationPolicy;
        }

        public void UpdateAuthorizationPolicy(IObject obj, object param)
        {
            (obj as IObjectEntity).LocalObjectManager.AuthorizationPolicy.UpdateParameter(param);
        }

        public void SetConflictResolvePolicy(IObject obj, Type conflictResolvePolicyType, object param)
        {
            (obj as IObjectEntity).LocalObjectManager.ConflictResolvePolicy =
                Activator.CreateInstance(conflictResolvePolicyType, new object[] { obj, param }) as ConflictResolvePolicy;
        }

        public void UpdateConflictResolvePolicy(IObject obj, object param)
        {
            (obj as IObjectEntity).LocalObjectManager.ConflictResolvePolicy.UpdateParameter(param);
        }

        #region IObjectManager Members

        public void StartWork()
        {
            // TODO
        }

        public IObjectTree ObjectTree
        {
            get
            {
                return _objectTree;
            }
            set
            {
                this._objectTree = value;
            }
        }

        public IInputManager InputManager
        {
            get
            {
                return _inputManager;
            }
            set
            {
                this._inputManager = value;
                _inputManager.InputDetected += OnInputDetected;
            }
        }

        public delegate void PutCommandsHandler(List<ICommand> cmds);

        public delegate IObject CreateObjectHandler(IObject owner, ObjectCreateParameter parameter);

        public delegate IObject CreateObjectHandler2(ObjectCreateParameter parameter);

        public IObject CreateObject(IObject owner, ObjectCreateParameter parameter)
        {
            UObjectEntity obj = CreateObject(parameter) as UObjectEntity;
            ObjectCommand insertCmd = new ObjectCommand(owner,
                ObjectCommandType.Insert, obj);
            List<ICommand> cmdList = new List<ICommand>();
            cmdList.Add(insertCmd);
            PutCommands(cmdList);
            return obj;
        }

        public IObject CreateObject(ObjectCreateParameter parameter)
        {
            UObjectEntity obj = new UObjectEntity(parameter);
            return obj;
        }


        public void PutCommands(List<ICommand> cmds)
        {
            // authorize commands

            // resolve conflicts

            // execute commands
            foreach (ICommand cmd in cmds)
            {
                if (cmd.Type == CommandType.SYSTEM)
                {
                    switch ((cmd as SystemCommand).SubType)
                    {
                        case SystemCommandType.Shutdown:
                            Application.Current.Shutdown((int)(cmd as SystemCommand).Param);
                            break;
                    }
                }

                if (cmd.Receiver == null)
                    continue;

                if (cmd.Type == CommandType.OBJECT)
                {
                    // handled by global object manager
                    if ((cmd as ObjectCommand).SubType == ObjectCommandType.Create)
                    {
                        ObjectCreateParameter param = (cmd as ObjectCommand).Param as ObjectCreateParameter;
                        UObjectEntity obj = new UObjectEntity(param);
                        ObjectCommand insertCmd = new ObjectCommand(cmd.Receiver, 
                            ObjectCommandType.Insert, obj);
                        List<ICommand> cmdList = new List<ICommand>();
                        cmdList.Add(insertCmd);
                        PutCommands(cmdList);
                        continue;
                    }
                    if ((cmd as ObjectCommand).SubType == ObjectCommandType.Insert)
                    {
                        UObjectEntity obj = (cmd as ObjectCommand).Param as UObjectEntity;
                        if (obj != null && !obj.OwnedObjects.Contains(obj))
                            (cmd.Receiver as UObjectEntity).Children.Add(obj);
                        obj.SetOwner2(cmd.Receiver as UObjectEntity);
                    }
                    else if ((cmd as ObjectCommand).SubType == ObjectCommandType.Remove)
                    {
                        UObjectEntity obj = (cmd as ObjectCommand).Param as UObjectEntity;
                        (cmd.Receiver as UObjectEntity).Children.Remove(obj);
                        obj.SetOwner2(null);
                    }
                    else if ((cmd as ObjectCommand).SubType == ObjectCommandType.Close)
                    {
                        UObjectEntity obj = (cmd as ObjectCommand).Param as UObjectEntity;
                        (cmd.Receiver as UObjectEntity).Children.Remove(obj);
                    }

                    // handled by local object manager
                    IObject receiver = null;
                    if ((cmd as ObjectCommand).SubType == ObjectCommandType.Insert || 
                        (cmd as ObjectCommand).SubType == ObjectCommandType.Remove ||
                        (cmd as ObjectCommand).SubType == ObjectCommandType.Close ||
                        (cmd as ObjectCommand).SubType == ObjectCommandType.Join)
                        receiver = cmd.Receiver;
                    else
                        receiver = ObjectTree.GetParent(cmd.Receiver) as IObject;
                    // TODO: deal with the root
                    if (receiver == null)
                        _defaultLocalObjectManager.ExecuateCommand(cmd as ObjectCommand);
                    else if (receiver is IObjectEntity)
                        (receiver as IObjectEntity).LocalObjectManager.ExecuateCommand(cmd as ObjectCommand);
                }
            }
        }

        #endregion
    }
}
